Skip to content

feat: gene pages: explore a gene's bionym graph on its page (#1945) - #2007

Open
NoopDog wants to merge 3 commits into
mainfrom
noopdog/1945-bionym-graph
Open

NoopDog wants to merge 3 commits into
mainfrom
noopdog/1945-bionym-graph

Conversation

@NoopDog

@NoopDog NoopDog commented Nov 14, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #1945

Note

Like #1944, this is early-stage: it puts BioNym's graph on the gene page with BioNym's own components so we can try it on real data. How the graph is presented is for the UX review in #1943 to design.

What changed

  • API: GET /api/v1/genes/{gene_uid}/bionym/graph (app/services/bionym_graphs.py) returns every node and edge in the gene's checked-in BioNym graph, ortholog-group members included:

    • each node with its id, type and label, and its link only when it is https:;
    • each edge with its subject, kind (predicate), object and confidence.

    A gene with no graph gets a 404. The graph is built when the graphs load. A graph with an edge that ends at a node it doesn't have fails the load and the backend tests, so it never reaches the page.

  • Gene page, Claims and Graph tabs: the "Evidence gathered by BioNym" section now has two tabs, chosen by the URL hash (#claims, #graph).

  • The graph explorer (BionymSection/components/GraphPanel/):

    • BioNym's bar chart of the graph's nodes by type, labelled "Every node in BioNym's graph, by type". A bar click hides or shows that type, and a hidden type gets a chip to show it again.
    • BioNym's network, drawn through a thin React wrapper, with a Columns / Force layout switch and zoom in, zoom out and fit buttons.
    • A count of the nodes and edges drawn at the minimum confidence, for example "1002 nodes and 1069 of 6536 edges" for Kelch13 at 0.8.
    • A switch for each kind of edge, with its count.
    • Our own panel for a clicked node: its label, its type, an https: link to its source, and its edges, each with its confidence. It closes when you click empty space or another node.
  • Types: @types/bionym-components.d.ts types the parts of bionym-components the explorer uses, since the package ships none.

Why

#1944 put BioNym's claims on the gene page as a list. The rest of a BioNym graph doesn't fit a list: how the gene connects to its orthologs, assemblies, datasets, papers and conditions. This is work item 2 of "Gene pages: show the evidence BioNym gathers about a gene" (#1943).

Assumptions I made

  • Kinds of edge hidden by default. Four kinds start hidden: has_member, same_as, has_candidate_gene and annotated_in. They were chosen on the three checked-in graphs at the default 0.8:

    • has_member links the gene's ortholog group to every protein in it (2,460 for Kelch13);
    • same_as links aliases of one entity;
    • has_candidate_gene links candidate genes in related assemblies;
    • annotated_in links those genes to the assemblies they're annotated in.

    Hiding them takes Kelch13 from 5,111 nodes to 1,002, CRT from 2,386 to 1,452, and AMA1 from 1,475 to 1,061. Kelch13's gene column drops from 1,590 genes to 35. Each kind can be shown again with its switch. Hiding kinds of edge is the only way of taming the graph this PR tries. Collapsing the ortholog group into one node, or starting from the gene and expanding outwards, are left for the UX review.

  • The Columns layout is the default. The Force layout is offered but not the default, because of the library bugs below.

  • The Graph tab stays on the page once opened. Switching to Claims hides it rather than removing it. Its filters, layout and selection survive a tab switch, and the network isn't drawn again.

  • The count follows the network. The network redraws once the slider has rested for 150 ms, so a drag redraws it only once. The count changes together with the network, not ahead of it.

  • The bar chart counts the whole graph, not what the network draws, so every type keeps a bar to click. Its label says so.

  • Tab changes go through Next's router, and the tab clicked shows at once. Next writes the new URL hash with no hashchange event, so the section sees it only when Next renders the navigation; until Next's last navigation is done, the section shows the tab clicked. A quick second tab click isn't lost, the back button moves between tabs, and Back to the gene page from a page it links to shows the gene page again.

  • Known bugs in bionym-components 0.1.1, reported upstream and to be fixed in a library PR:

  • No close button on the node panel. The network can drop its selection only by redrawing, which moves the nodes in the Force layout, so a close button would either leave the node highlighted or move the graph. It comes back with the library fix, which adds a way to clear the selection.

  • The node and edge counts use our own copy of BioNym's confidence rule (countShown in GraphPanel/utils.ts). The library's filterByConfidence can only be reached today through the library's main entry, which loads D3, and Jest can't load D3. The follow-up after the library fix switches to the library's function.

  • Not in scope: publishing graphs to the gene data store (Gene pages: publish BioNym graphs to the gene data store and serve them through a pin #1947), and keyboard access to the network, which belongs in the library.

How to verify

The gene snapshot bucket serves only the servers, so first build a local snapshot as catalog/docs/gene-catalog/gene-snapshot-release-design.md describes. From catalog/py_package, with the catalog build's requirements installed:

cd catalog/py_package
python -m catalog_build.genes.build_gene_snapshot \
  --assembly GCF_000002765.6 \
  --gff3 https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/000/002/765/GCF_000002765.6_GCA_000002765/GCF_000002765.6_GCA_000002765_genomic.gff.gz \
  --out ~/genes-3d7.duckdb

Then run the API with GENE_SNAPSHOT_PATH=~/genes-3d7.duckdb, run the site, and open Kelch13 (PF3D7_1343700): /data/genes/detail?uid=f0adadd3-973b-5c61-9e11-7c688b4e0895&gene-pages=true.

  1. See the Claims and Graph tabs under the gene's main information, with the claims list on Claims. "PfK13 mutations are associated with artemisinin resistance" ends with "(confidence 0.99)", and hovering a claim shows its quote. In the browser's network tab, see that no bionym-components or D3 files have loaded.
  2. Open the Graph tab. See the graph's JavaScript load now, and the URL end in #graph. See the bar chart, the network in the Columns layout, and "1002 nodes and 1069 of 6536 edges".
  3. Under "Kinds of edge", turn on has_member (2460) and see the count rise as the ortholog group's member proteins appear. Turn it off again.
  4. Move the slider to 0.95. See edges and nodes drop out, and the count fall once the slider rests. Go to the Claims tab and see the same 0.95 there.
  5. Click a paper node in the Publication column. See the panel list its edges, each with its confidence, and a Source link to PubMed. Click empty space in the network and see the panel close.
  6. Click Force and see the force layout draw. Zoom in and out with the buttons, and press fit to see the whole graph. Node names don't appear when you zoom, and some clicks are lost; see the known bugs above.
  7. Set up the Graph tab (turn an edge kind on, choose the Force layout), go to Claims and back, and see it as you left it.
  8. On the Graph tab, follow the Assembly link (GCF_000002765.6) in the gene's main information, then press the browser's Back button. See the gene page again, on the Graph tab.

Definition of done, mapped to these steps:

  • The gene page has Claims and Graph tabs under its main information. The Claims tab holds the claims list from Gene pages: show BioNym's claims about a gene, from graphs checked into the repo #1944, with each claim's confidence at its end. Step 1.
  • The Graph tab shows the overview strip, the network and the detail panel. Its JavaScript and D3 load only when the tab is first opened. Steps 1, 2 and 5.
  • The Graph tab receives the full graph, ortholog-group members included. Switches hide and show each kind of edge, and the defaults chosen are explained in the PR. Step 3, and "Kinds of edge hidden by default" above.
  • The confidence slider filters the network as it does the claims list. Step 4.
  • Clicking a node shows its edges with their confidence, and links only to https: sources. A test covers a node whose URL isn't https:. Step 5. The tests are "links no node whose URL isn't https:" in tests/views/bionymGraphPanel.test.tsx, and test_bionym_links_other_than_https_are_dropped in backend/api/tests/test_genes_api.py.
  • The layout switch and the zoom and fit buttons work. Step 6, with the library's known bugs.

Screenshots

Attach these from ~/Downloads/brc-analytics-1945/:

  • brc-analytics-1945-claims-tab-desktop.png: the Claims tab, each claim with its confidence.
  • brc-analytics-1945-graph-tab-desktop.png: the Graph tab at its defaults, in the Columns layout.
  • brc-analytics-1945-node-detail-desktop.png: a paper selected, with its edges in the panel.
  • brc-analytics-1945-force-layout-desktop.png: the Force layout after fit, without node names (Show node names when zoomed in on the force layout, and let the page scroll past the network d-callan/bionym#5).
  • brc-analytics-1945-graph-page-full-desktop.png: the whole gene page on the Graph tab.
  • brc-analytics-1945-claims-tab-phone.png, brc-analytics-1945-graph-tab-phone.png, brc-analytics-1945-node-detail-phone.png: the same on a phone, with the node panel under the network.
  • brc-analytics-1945-graph-tab-desktop.webm: the slider, a paper node, the Force layout, then Claims and back, with the Graph tab as it was left.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FsksmWc58SyK9E2LDM4KUU
🐦 Built with cc-claude-tools

Add a Graph tab beside the Claims tab in the gene page's BioNym section. It
draws the gene's BioNym graph with bionym-components: a bar chart of the
whole graph's nodes by type (a bar click hides or shows a type), the network
in a columns or force layout, switches for kinds of edge, and a panel with a
clicked node's edges. The tabs share one minimum confidence.

The API serves the graph at /api/v1/genes/{gene_uid}/bionym/graph, from the
graphs checked into the repo. The tab's code loads only when it is first
opened, and the panel then stays on the page, hidden, so a tab switch keeps
its filters, layout and selection. Tab changes go through the History API so
a quick second click isn't lost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsksmWc58SyK9E2LDM4KUU
Co-authored-by: cc-claude-tools <cc-claude-tools@clevercanary.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Tab selection drops Next Pages Router history metadata, so navigating away and pressing Back can restore the gene URL while leaving the other page rendered.

1 open issue
What changed in this PR

Extends the gene page’s BioNym evidence section from a claims list to an interactive graph explorer, implementing the next stage of #1943.

Changes:

  • Adds a full-graph API with node-reference validation and HTTPS-only source links.
  • Introduces Claims and Graph tabs with shared confidence filtering, restoring confidence scores on claims.
  • Adds a lazy-loaded graph explorer with filters, layouts, zoom controls, node details, types, and tests.
File Description
tests/​views/​geneDetailView.test.tsx Tests tabs, confidence scores, and graph persistence.
tests/​views/​bionymGraphPanel.test.tsx Tests graph controls, filtering, details, and links.
tests/​hooks/​useGeneBionymGraph.test.tsx Tests graph fetching and loading states.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​utils.ts Adds confidence formatting and tab-hash helpers.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​types.ts Defines tabs and shared confidence props.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​constants.ts Defines Claims and Graph tabs.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​utils.ts Adds graph filtering, counting, and link validation.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​types.ts Defines explorer and graph-detail types.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​hooks/​useSettledValue.ts Debounces confidence-driven redraws.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​graphPanel.tsx Coordinates graph loading, filters, and selection.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​graphPanel.styles.ts Styles the responsive explorer and controls.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​constants.ts Defines hidden-edge defaults and debounce timing.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​components/​OverviewView/​types.ts Defines overview props.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​components/​OverviewView/​overviewView.tsx Wraps BioNym’s node-type chart.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​components/​NodeDetail/​types.ts Defines node-detail props.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​components/​NodeDetail/​nodeDetail.tsx Displays selected-node edges, confidence, and source.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​components/​NetworkView/​types.ts Defines network props and selection callbacks.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​components/​NetworkView/​networkView.tsx Wraps the network with layout and zoom controls.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​components/​EdgeKindSwitches/​types.ts Defines edge-filter props.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphPanel/​components/​EdgeKindSwitches/​edgeKindSwitches.tsx Adds edge-kind switches with counts.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphLoading/​types.ts Defines loading-error props.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​GraphLoading/​graphLoading.tsx Displays graph loading and failure messages.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​ConfidenceControl/​types.ts Defines shared slider props.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​ConfidenceControl/​confidenceControl.tsx Extracts the reusable confidence slider.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​ClaimsPanel/​types.ts Defines extracted claims-panel props.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​components/​ClaimsPanel/​claimsPanel.tsx Moves claims into a panel and restores scores.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​bionymSection.tsx Adds tabs and persistent, lazy-loaded graph content.
sites/​brc-analytics/​views/​GeneDetailView/​components/​BionymSection/​bionymSection.styles.ts Renames the slider’s styled container.
sites/​brc-analytics/​tsconfig.json Includes BioNym component declarations.
packages/​shared/​services/​genes/​types.ts Defines the graph API response types.
packages/​shared/​services/​genes/​api.ts Adds graph fetching with missing-graph handling.
packages/​shared/​services/​api-client/​api-client.ts Adds the graph endpoint client method.
packages/​shared/​hooks/​useGeneBionymGraph.ts Adds cached graph loading through React Query.
package.json Adds bionym-components 0.1.1.
package-lock.json Locks the BioNym dependency.
backend/​api/​tests/​test_genes_api.py Tests graph responses, validation, and safe links.
backend/​api/​app/​services/​bionym_graphs.py Builds and caches validated graph views.
backend/​api/​app/​models/​genes.py Adds graph response models.
backend/​api/​app/​api/​v1/​genes.py Exposes the full-graph endpoint.
@types/​bionym-components.d.ts Types the BioNym interfaces used by the explorer.

Review effort: Balanced

…nders the gene page

Choosing a tab pushed a history entry with no state, so after leaving the
gene page from a tab, Back restored the gene URL but left the other page
rendered. Tabs now navigate with Next's router, and the section shows the
tab clicked until the last navigation is done, so a quick second click
isn't lost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsksmWc58SyK9E2LDM4KUU
Co-authored-by: cc-claude-tools <cc-claude-tools@clevercanary.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues were identified for the BioNym graph explorer changes.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

…ng nodes, check zoom factors

- `filterGraph` and `nodeEdges` throw when an edge ends at an id that isn't
  a node, rather than defaulting; `NodeEdge.other` is no longer optional.
- The zoom test asserts the factors each button passes; `ZOOM_STEP` moves to
  the explorer's constants.
- `toggled` moves to the explorer's `utils.ts`.
- `build_graph`'s docstring names the `ValueError` it raises.
- The tab hook's docstring and the router mock's comment say how Next
  writes a hash-only navigation; the node panel's docstring says why it has
  no close button.
- Assertions that only checked the test's own hash helper are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FsksmWc58SyK9E2LDM4KUU
Co-authored-by: cc-claude-tools <cc-claude-tools@clevercanary.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Human browser validation is needed across all three full D3 graphs because tests mock BioNym components and the PR accepts force-layout freezes and incomplete cleanup in the pinned library.

No open issues 🎉

Review effort: Balanced

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Gene pages: explore a gene's BioNym graph on its page

2 participants